package dao

import (
	"bytes"
	"fmt"
	"game/game-db/orm/column"
	"game/game-db/orm/metag"
	"strings"
	"time"
)

// 在构建表的时候，如果需要用到时间的字段，需要使用DDLTime
type DDLTime struct {
	time.Time
}

func (d *DDLTime) UnmarshalJSON(data []byte) error {
	data = bytes.Trim(data, "\"")
	if string(data) == "" {
		return nil
	}
	t, err := time.Parse("2006-01-02 15:04:05", string(data))
	if err == nil {
		*d = DDLTime{t}
	}
	return err
}

// 查询某个库中的数据表的SQL
func TableExistSql(tableName string) string {
	tableExistSql := "SHOW TABLE STATUS WHERE NAME='%s';"
	return fmt.Sprintf(tableExistSql, tableName)
}

// 数据表信息
type TableExist struct {
	Name string `orm:"name=Name"`
	// Engine          string `json:"Engine"`
	// Version int `orm:"name=Version"`
	// Row_format      string `json:"Row_format"`
	// Rows            int    `json:"Rows"`
	// Avg_row_length  int    `json:"Avg_row_length"`
	// Data_length     int    `json:"Data_length"`
	// Max_data_length int    `json:"Max_data_length"`
	// Index_length    int    `json:"Index_length"`
	// Data_free       int    `json:"Data_free"`
	// Auto_increment  int    `json:"Auto_increment"`
	// Create_time     DDLTime `json:"Create_time"`
	// Update_time     DDLTime `json:"Update_time"`
	// Check_time      DDLTime `json:"Check_time"`
	// Collation       string  `json:"Collation"`
	// Checksum        int     `json:"Checksum"`
	// Create_options  string  `json:"Create_options"`
	Comment string `orm:"name=Comment"`
}

// 查询某个表中索引的SQL
func KeysSql(tableName string) string {
	keysSql := "SHOW KEYS FROM `%s`"
	return fmt.Sprintf(keysSql, tableName)
}

// 索引信息
type TableKey struct {
	Table      string `orm:"name=Table"`
	NonUnique  int    `orm:"name=Non_unique"`
	KeyName    string `orm:"name=Key_name"`
	SeqInIndex int    `orm:"name=Seq_in_index"`
	ColumnName string `orm:"name=Column_name"`
}

// 丢弃主键
func DropPrimaryKeySql(tableName string) string {
	dropPrimaryKey := "ALTER TABLE `%s` DROP PRIMARY KEY;"
	return fmt.Sprintf(dropPrimaryKey, tableName)
}

// 创建主键的SQL
func CreatePrimaryKeySql(keyMeta *column.PrimaryKeyColumnMeta, tableName string) string {

	if keyMeta.KeyStrategy() == metag.AUTO || keyMeta.KeyStrategy() == metag.AUTOWIRE {
		// 创建自增主键的SQL
		createAutoPrimaryKey := "ALTER TABLE `%s` MODIFY COLUMN `%s` %s NOT NULL AUTO_INCREMENT COMMENT '%s', ADD PRIMARY KEY (`%s`);"
		if keyMeta.FieldType() == "int32" {
			return fmt.Sprintf(createAutoPrimaryKey, tableName, keyMeta.ColumnName(), "int", keyMeta.Comment(), keyMeta.ColumnName())
		} else if keyMeta.FieldType() == "int64" {
			return fmt.Sprintf(createAutoPrimaryKey, tableName, keyMeta.ColumnName(), "bigint", keyMeta.Comment(), keyMeta.ColumnName())
		} else {
			panic("只支持int32,int64的字段成为自增主键")
		}
	} else {
		// 创建非自增主键的SQL
		createPrimaryKey := "ALTER TABLE `%s` MODIFY COLUMN `%s` %s NOT NULL COMMENT '%s', ADD PRIMARY KEY (`%s`);"
		if keyMeta.FieldType() == "int32" {
			return fmt.Sprintf(createPrimaryKey, tableName, keyMeta.ColumnName(), "int", keyMeta.Comment(), keyMeta.ColumnName())
		} else if keyMeta.FieldType() == "int64" {
			return fmt.Sprintf(createPrimaryKey, tableName, keyMeta.ColumnName(), "bigint", keyMeta.Comment(), keyMeta.ColumnName())
		} else if keyMeta.FieldType() == "string" {
			columnDefine := fmt.Sprintf("varchar(%v)", keyMeta.Length())
			return fmt.Sprintf(createPrimaryKey, tableName, keyMeta.ColumnName(), columnDefine, keyMeta.Comment(), keyMeta.ColumnName())
		} else {
			panic("只支持int32,int64与string的字段成为主键")
		}
	}
}

// 修改列定义的SQL
func ModifyColumnSql(tableName string, columnDefine string) string {
	modifyColumn := "ALTER TABLE `%s` MODIFY COLUMN %s;"
	return fmt.Sprintf(modifyColumn, tableName, columnDefine)
}

type TableColumn struct {
	Field string `orm:"name=Field"`
	Type  string `orm:"name=Type"`
	Extra string `orm:"name=Extra"`
}

// 查看表中列的描述信息
func ShowColumnsSql(tableName string) string {
	showColumns := "DESCRIBE `%s`;"
	return fmt.Sprintf(showColumns, tableName)
}

// 删除列的SQL
func DropColumn(tableName string, columnName string) string {
	dropColumn := "ALTER TABLE `%s` DROP COLUMN `%s`;"
	return fmt.Sprintf(dropColumn, tableName, columnName)
}

// 新增列的SQL
func AddColumn(tableName string, columnDefine string) string {
	addColumn := "ALTER TABLE `%s` ADD COLUMN %s;"
	return fmt.Sprintf(addColumn, tableName, columnDefine)
}

// 新增索引的SQL
func AddIndexSql(tableName string, indexType string, indexName string, indexColumns ...string) string {
	addIndex := "ALTER TABLE `%s` ADD %v INDEX `%s` (%s);"
	columnJoins := strings.Join(indexColumns, ",")
	return fmt.Sprintf(addIndex, tableName, indexType, indexName, columnJoins)
}

// 修改索引的SQL
func ModifyIndexSql(tableName string, indexType string, indexName string, indexColumns ...string) string {
	modifyIndex := "ALTER TABLE `%s` DROP INDEX `%s`, ADD %s INDEX `%s` (%s);"
	columnJoins := strings.Join(indexColumns, ",")
	return fmt.Sprintf(modifyIndex, tableName, indexName, indexType, indexName, columnJoins)
}

// 查询表中最大的ID
func SelectMaxId(idName string, tableName string) string {
	selectMaxId := "SELECT max(`%s`) AS maxid FROM `%s` LIMIT 1;"
	return fmt.Sprintf(selectMaxId, idName, tableName)
}

type TableMaxId struct {
	Maxid int64 `orm:"name=maxid"`
}

const MysqlVersionSql string = "SELECT VERSION() AS version;"

type MysqlVersion struct {
	Version string `orm:"name=version"`
}

// mysql5.x用这种方式来查自增主键
func TableAutoInc5(tableName string) string {
	tableAutoinc5 := "SHOW TABLE STATUS WHERE NAME='%s';"
	return fmt.Sprintf(tableAutoinc5, tableName)
}

// mysql8.x用这种方式来查自增主键
func TableAutoInc8(schemaName string, tableName string) string {
	tableAutoinc8 := "SELECT `AUTOINC` AS Auto_increment FROM `INFORMATION_SCHEMA`.`INNODB_TABLESTATS` WHERE `NAME`=`%s/%s`;"
	return fmt.Sprintf(tableAutoinc8, schemaName, tableName)
}

// mysql8.x也可以用先手动触发表的数据统计，再获取自增序列的方式来查询主键
func TableAnalyze8_2(tableName string) string {
	tableAnalyze8_2 := "ANALYZE TABLE `%s`;"
	return fmt.Sprintf(tableAnalyze8_2, tableName)
}

// 适用于mysql8.x，必须搭配TableAnalyze8_2才能生效
func TableAutoInc8_2(tableName string) string {
	tableAutoinc8_2 := "SHOW TABLE STATUS WHERE NAME='%s';"
	return fmt.Sprintf(tableAutoinc8_2, tableName)
}

type TableAutoIncrement struct {
	AutoIncrement int64 `orm:"name=Auto_increment"`
}

// 设置自增起始位置的DDL在golang不能用问号(?)传参的方式
func SetAutoIncrement(tableName string, autoinc int64) string {
	setAutoIncrement := "ALTER TABLE `%s` AUTO_INCREMENT=%v;"
	return fmt.Sprintf(setAutoIncrement, tableName, autoinc)
}
